declare type CompilerOptions = {
  warn?: Function, // allow customizing warning in different environments, e.g. node
  isIE?: boolean, // for detecting IE SVG innerHTML bug
  expectHTML?: boolean, // only false for non-web builds
  modules?: Array<ModuleOptions>, // platform specific modules, e.g. style, class
  staticKeys?: string, // a list of AST properties to be considered static, for optimization
  directives?: { [key: string]: Function }, // platform specific directives
  isUnaryTag?: (tag: string) => ?boolean, // check if a tag is unary for the platform
  isReservedTag?: (tag: string) => ?boolean, // check if a tag is a native for the platform
  mustUseProp?: (attr: string) => ?boolean, // check if an attribute should be bound as a property
  getTagNamespace?: (tag: string) => ?string, // check the namespace for a tag
  transforms?: Array<Function>, // a list of transforms on parsed AST before codegen
  preserveWhitespace?: boolean,

  // runtime user-configurable
  delimiters?: [string, string] // template delimiters
}

declare type CompiledResult = {
  ast: ?ASTElement,
  render: string,
  staticRenderFns: Array<string>,
  errors?: Array<string>
}

declare type CompiledFunctionResult = {
  render: Function,
  staticRenderFns: Array<Function>
}

declare type ModuleOptions = {
  transformNode: (el: ASTElement) => void, // transform an element's AST node
  genData: (el: ASTElement) => string, // generate extra data string for an element
  transformCode?: (el: ASTElement, code: string) => string, // further transform generated code for an element
  staticKeys?: Array<string> // AST properties to be considered static
}

declare type ASTElementHandler = {
  value: string,
  modifiers: ?{ [key: string]: true }
}

declare type ASTElementHandlers = {
  [key: string]: ASTElementHandler | Array<ASTElementHandler>
}

declare type ASTElementHooks = { [key: string]: Array<string> }

declare type ASTDirective = {
  name: string,
  value: ?string,
  arg: ?string,
  modifiers: ?{ [key: string]: true }
}

declare type ASTNode = ASTElement | ASTText | ASTExpression

declare type ASTElement = {
  type: 1,
  tag: string,
  attrsList: Array<{ name: string, value: string }>,
  attrsMap: { [key: string]: string | null },
  parent: ASTElement | void,
  children: Array<ASTNode>,

  static?: boolean,
  staticRoot?: boolean,
  staticProcessed?: boolean,

  text?: string,
  attrs?: Array<{ name: string, value: string }>,
  props?: Array<{ name: string, value: string }>,
  staticAttrs?: Array<{ name: string, value: string }>,
  plain?: boolean,
  pre?: true,
  ns?: string,

  component?: string,
  keepAlive?: boolean,
  inlineTemplate?: true,
  transitionMode?: string | null,
  slotName?: ?string,
  slotTarget?: ?string,

  ref?: string,
  refInFor?: boolean,

  if?: string,
  ifProcessed?: boolean,
  else?: true,
  elseBlock?: ASTElement,

  for?: string,
  forProcessed?: boolean,
  key?: string,
  alias?: string,
  iterator1?: string,
  iterator2?: string,

  staticClass?: string,
  classBinding?: string,
  styleBinding?: string,
  hooks?: ASTElementHooks,
  events?: ASTElementHandlers,

  transition?: string | true,
  transitionOnAppear?: boolean,

  directives?: Array<ASTDirective>,

  forbidden?: true,
  once?: true
}

declare type ASTExpression = {
  type: 2,
  expression: string,
  text: string,
  static?: boolean
}

declare type ASTText = {
  type: 3,
  text: string,
  static?: boolean
}

// SFC-parser related declarations

// an object format describing a single-file component.
declare type SFCDescriptor = {
  template: ?SFCBlock,
  script: ?SFCBlock,
  styles: Array<SFCBlock>
}

declare type SFCBlock = {
  type: string,
  content: string,
  start?: number,
  end?: number,
  lang?: string,
  src?: string,
  scoped?: boolean
}
